package com.yoooya.base.utils;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.yoooya.base.type.ThumbnailType;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Objects;

/**
 * 图片工具类
 * 
 * @author Sun Yijing<br />
 *         Copyright © Xiamen Yoooya NetWorks Co.,Ltd.
 * @since yoooya software platform v1.0.0
 * @version 1.0.0 <br />
 *          <table border="1" cellpadding="3" cellspacing="0">
 *          <tr>
 *          <th align="left" colspan="3"><b>修改历史</b></th>
 *          </tr>
 *          <tr>
 *          <td>修改日期</td>
 *          <td>修改人</td>
 *          <td>修改描述</td>
 *          </tr>
 *          <tr>
 *          <td>2018-6-20</td>
 *          <td>Sun Yijing</td>
 *          <td>新建</td>
 *          </tr>
 *          </table>
 */
public class ImageUtils {

	private ImageUtils() {
	}

	private final static float DEFAULT_QUALITY = 1.0f;

	private final static int MAP_RANGE = 256;

	/**
	 *  旋转图片，且当width<height时旋转
	 * @author cjianquan
	 * @date 2020/1/17
	 * @param [file, angel]
	 * @return java.io.File
	 */
	public static File rotateImage(File file,int angel){
		try{
			BufferedImage image = ImageIO.read(file);
			int width = image.getWidth();
			int height = image.getHeight();
			if(height<=width){
				return file;
			}

			// 计算旋转后图片的尺寸
			Rectangle rect_des = calcRotatedSize(new Rectangle(new Dimension(width, height)), angel);

			BufferedImage res = null;
			res = new BufferedImage(rect_des.width, rect_des.height,BufferedImage.TYPE_INT_RGB);
			Graphics2D g2 = res.createGraphics();
			// 进行转换
			g2.translate((rect_des.width - width) / 2,(rect_des.height - height) / 2);
			g2.rotate(Math.toRadians(angel),width/2, height/2);

			g2.drawImage(image, null, null);

			String path = ImageUtils.class.getResource("/").getPath()+"temp/";
			File pathFile=new File(path);
			if(!pathFile.exists()){
				pathFile.mkdirs();
			}
			System.out.println("path="+path);
			File rtnFile = new File(path+""+IdUtils.id()+".jpg");
			ImageIO.write(res,"jpg",rtnFile);
			return rtnFile;
		}catch (Exception e){
			e.printStackTrace();
		}

		return null;

	}

	public static Rectangle calcRotatedSize(Rectangle src, int angel) {
		// 如果旋转的角度大于90度做相应的转换
		if (angel >= 90) {
			if (angel / 90 % 2 == 1) {
				int temp = src.height;
				src.height = src.width;
				src.width = temp;
			}
			angel = angel % 90;
		}

		double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
		double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
		double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
		double angel_dalta_width = Math.atan((double) src.height / src.width);
		double angel_dalta_height = Math.atan((double) src.width / src.height);

		int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_width));
		int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_height));
		int des_width = src.width + len_dalta_width * 2;
		int des_height = src.height + len_dalta_height * 2;
		return new Rectangle(new Dimension(des_width, des_height));
	}



	/**
	 * 合并图片
	 * @author cjianquan
	 * @date 2020/1/17
	 * @param [url1, url2]
	 * @return java.io.File
	 */
	public static File mergeImage(String url1,String url2,int scaledWidth){
		String path = ImageUtils.class.getResource("/").getPath()+"temp/";
		File pathFile=new File(path);
		if(!pathFile.exists()){
			pathFile.mkdirs();
		}
		System.out.println("path="+path);
		File file = new File(path+""+IdUtils.id()+".jpg");
		try{
			BufferedImage img1 = ImageIO.read(new URL(url1));
			BufferedImage img2 = ImageIO.read(new URL(url2));

			int srcWidth1 = img1.getWidth();
			int srcHeight1 = img1.getHeight();
			double percent1 = Double.parseDouble(""+scaledWidth)/Double.parseDouble(""+srcWidth1);
			int height1 = (int)(srcHeight1 * percent1);

			int srcWidth2 = img2.getWidth();
			int srcHeight2 = img2.getHeight();
			double percent2 = Double.parseDouble(""+scaledWidth)/Double.parseDouble(""+srcWidth2);
			int height2 = (int)(srcHeight2 * percent2);


			int width = scaledWidth;
			int height = height1+height2;

			BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);//创建图片

			Graphics g = img.getGraphics();//开启画图


			g.drawImage(img1.getScaledInstance(scaledWidth, height1, Image.SCALE_DEFAULT), 0, 0, null); // 绘制缩小后的图
			g.drawImage(img2.getScaledInstance(scaledWidth, height2, Image.SCALE_DEFAULT), 0, height1, null); // 绘制缩小后的图

			g.dispose();

			ImageIO.write(img, "jpg", file);

		}catch (Exception e){
			e.printStackTrace();
		}

		return file;
	}

	/**
	 * 图片缩放处理  按比例缩放
	 * @author cjianquan
	 * @date 2020/1/18
	 * @param [urlPath, toWidth]
	 * @return java.io.File
	 */
	public static File scaledImageByUrl(String urlPath, int toWidth)  {

		File file = null;
		try{
			URL url = new URL(urlPath);
			// 连接类的父类，抽象类
			URLConnection urlConnection = url.openConnection();
			// http的连接类
			HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
			//设置超时
			httpURLConnection.setConnectTimeout(1000*5);
			//设置请求方式，默认是GET
			httpURLConnection.setRequestMethod("POST");
			// 设置字符编码
			httpURLConnection.setRequestProperty("Charset", "UTF-8");
			// 打开到此 URL引用的资源的通信链接（如果尚未建立这样的连接）。
			httpURLConnection.connect();
			// 文件大小
			int fileLength = httpURLConnection.getContentLength();

			// 建立链接从请求中获取数据
			URLConnection con = url.openConnection();
			BufferedInputStream bin = new BufferedInputStream(httpURLConnection.getInputStream());
			// 指定文件名称(有需求可以自定义)
			String fileFullName = IdUtils.id()+".png";
			String path = ImageUtils.class.getResource("/").getPath()+"temp/";
			File pathFile=new File(path);
			if(!pathFile.exists()){
				pathFile.mkdirs();
			}
			// 指定存放位置(有需求可以自定义)
			String filePath = path + fileFullName;
			file = new File(filePath);

			OutputStream out = new FileOutputStream(file);
			int size = 0;
			int len = 0;
			byte[] buf = new byte[2048];
			while ((size = bin.read(buf)) != -1) {
				len += size;
				out.write(buf, 0, size);
			}
			// 关闭资源
			bin.close();
			out.close();


			BufferedImage srcImage = ImageIO.read(file);
			int srcWidth = srcImage.getWidth();
			int srcHeight = srcImage.getHeight();
			double percent = Double.parseDouble(""+toWidth)/Double.parseDouble(""+srcWidth);

			int toHeight = (int)(srcHeight * percent);

			BufferedImage targetImage = new BufferedImage(toWidth, toHeight,BufferedImage.TYPE_INT_RGB);
			targetImage.getGraphics().drawImage(srcImage.getScaledInstance(toWidth, toHeight,Image.SCALE_SMOOTH), 0, 0, null);



			File nImage = new File(path+""+IdUtils.id()+".png");
			if(!nImage.exists()){
				nImage.createNewFile();
			}
			FileOutputStream newImage = new FileOutputStream(nImage);
			JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(newImage);
			JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(targetImage);
			jep.setQuality(DEFAULT_QUALITY, true);
			encoder.encode(targetImage, jep);
			newImage.close();

			return nImage;
		}catch (Exception e){
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 图片缩放处理  按比例缩放
	 * @author cjianquan
	 * @date 2020/1/11
	 * @param [oImage, toWidth, nImage]
	 * @return void
	 */
	public static File scaledImage(File oImage, int toWidth) throws IOException {
		BufferedImage srcImage = ImageIO.read(oImage);
		int srcWidth = srcImage.getWidth();
		int srcHeight = srcImage.getHeight();
		double percent = Double.parseDouble(""+toWidth)/Double.parseDouble(""+srcWidth);

		int toHeight = (int)(srcHeight * percent);

		BufferedImage targetImage = new BufferedImage(toWidth, toHeight, BufferedImage.TYPE_INT_RGB);
		targetImage.getGraphics().drawImage(
				srcImage.getScaledInstance(toWidth, toHeight, Image.SCALE_SMOOTH), 0, 0, null);

		String path = ImageUtils.class.getResource("/").getPath()+"temp/";
		File pathFile=new File(path);
		if(!pathFile.exists()){
			pathFile.mkdirs();
		}

		File nImage = new File(path+""+IdUtils.id()+".png");
		if(!nImage.exists()){
			nImage.createNewFile();
		}
		FileOutputStream newImage = new FileOutputStream(nImage);
		JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(newImage);
		JPEGEncodeParam jep = JPEGCodec
				.getDefaultJPEGEncodeParam(targetImage);
		jep.setQuality(DEFAULT_QUALITY, true);
		encoder.encode(targetImage, jep);
		newImage.close();

		return nImage;
	}

	/**
	 * 图片缩放处理
	 */
	public static void scaledImage(File oImage, int toWidth, int toHeight,File nImage) throws IOException {
		BufferedImage srcImage = ImageIO.read(oImage);
		int srcWidth = srcImage.getWidth();
		int srcHeight = srcImage.getHeight();
		if (srcWidth <= toWidth && srcHeight <= toHeight) {
			BufferedImage targetImage = new BufferedImage(toWidth, toHeight,BufferedImage.TYPE_INT_RGB);
			targetImage.getGraphics().drawImage(
					srcImage.getScaledInstance(toWidth, toHeight, Image.SCALE_SMOOTH), 0, 0, null);
			FileOutputStream newImage = new FileOutputStream(nImage);
			JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(newImage);
			JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(targetImage);
			jep.setQuality(DEFAULT_QUALITY, true);
			encoder.encode(targetImage, jep);
			newImage.close();
		} else {
			if (srcWidth > srcHeight) {
				toHeight = (toWidth * srcHeight) / srcWidth;
			} else {
				toWidth = (toWidth * srcWidth) / srcHeight;
			}
			BufferedImage targetImage = new BufferedImage(toWidth, toHeight,BufferedImage.TYPE_INT_RGB);
			targetImage.getGraphics().drawImage(srcImage.getScaledInstance(toWidth, toHeight,Image.SCALE_SMOOTH), 0, 0, null);
			FileOutputStream newImage = new FileOutputStream(nImage);
			JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(newImage);
			JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(targetImage);
			jep.setQuality(DEFAULT_QUALITY, true);
			encoder.encode(targetImage, jep);
			newImage.close();
		}
	}

	/**
	 * 图片缩放处理
	 */
	public static void scaledImage(File oImage, File nImage, int toWidth,float quality) throws IOException {
		if (quality > 1 || quality < 0) {
			throw new IllegalArgumentException("Quality has to be between 0 and 1");
		}

		ImageIcon ii = new ImageIcon(oImage.getCanonicalPath());
		Image i = ii.getImage();
		Image targetImage;
		int iWidth = i.getWidth(null);
		int iHeight = i.getHeight(null);
		if (iWidth > iHeight) {
			targetImage = i.getScaledInstance(toWidth, (toWidth * iHeight)/ iWidth, Image.SCALE_SMOOTH);
		} else {
			targetImage = i.getScaledInstance((toWidth * iWidth) / iHeight,toWidth, Image.SCALE_SMOOTH);
		}
		Image temp = new ImageIcon(targetImage).getImage();
		BufferedImage bufferedImage = new BufferedImage(temp.getWidth(null),temp.getHeight(null), BufferedImage.TYPE_INT_RGB);
		Graphics g = bufferedImage.createGraphics();
		g.setColor(Color.white);
		g.fillRect(0, 0, temp.getWidth(null), temp.getHeight(null));
		g.drawImage(temp, 0, 0, null);
		g.dispose();

		float softenFactor = 0.05f;
		float[] softenArray = { 0, softenFactor, 0, softenFactor,1 - (softenFactor * 4), softenFactor, 0, softenFactor, 0 };
		Kernel kernel = new Kernel(3, 3, softenArray);
		ConvolveOp cOp = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
		bufferedImage = cOp.filter(bufferedImage, null);

		FileOutputStream out = new FileOutputStream(nImage);
		JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
		JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bufferedImage);
		param.setQuality(quality, true);
		encoder.setJPEGEncodeParam(param);
		encoder.encode(bufferedImage);
	}

	/**
	 * * 图片上传处理
	 * 
	 * @param file
	 *            图片文件
	 * @param maxSize
	 *            图片值大值
	 * @param allowFiles
	 * @param t
	 * @param rootPath
	 * @param domain
	 * @return
	 */
	public static ImgResponseObj handle(MultipartFile file, long maxSize,
			String[] allowFiles, String t, String rootPath, String domain,
			int imageMaxWidth) {
		ImgResponseObj resp = new ImgResponseObj();
		if (file.isEmpty()) {
			resp.setState("未包含文件上传域");
		} else if (file.getSize() > maxSize) {
			resp.setState("文件大小超出限制");
		} else {
			String originalName = file.getOriginalFilename();
			if (FilenameUtils.isExtension(originalName.toLowerCase(),allowFiles)) {
				long id = IdUtils.id();
				long hash = (id % MAP_RANGE) + 1;
				String fileFormat = FilenameUtils.getExtension(originalName);
				String fileName = id + "." + fileFormat;
				// 原图
				int ordinal = ThumbnailType.Original.ordinal();
				File path = FileUtils.getFile(rootPath,String.valueOf(ordinal), String.valueOf(hash));
				File ordinalFile = FileUtils.getFile(path, fileName);
				try {
					FileUtils.forceMkdir(path);
					file.transferTo(ordinalFile);
					try {
						BufferedImage srcImage = ImageIO.read(ordinalFile);
						if (srcImage.getWidth() > imageMaxWidth) {
							ImageUtils.scaledImage(ordinalFile, imageMaxWidth,imageMaxWidth, ordinalFile);
						}
					} catch (IOException e) {
					}
					// 图片缩略处理
					if (StringUtils.isNotBlank(t)) {
						String[] thumbnails = StringUtils.split(t);
						for (String thumbnail : thumbnails) {
							if (StringUtils.isNumericSpace(thumbnail)) {
								ThumbnailType thumbnailType = ThumbnailType.valueOf(Integer.parseInt(StringUtils.trim(thumbnail)));
								if (Objects.nonNull(thumbnailType)) {
									path = FileUtils.getFile(rootPath, String.valueOf(thumbnailType.ordinal()),String.valueOf(hash));
									FileUtils.forceMkdir(path);
									File targetFile = FileUtils.getFile(path,fileName);
									ImageUtils.scaledImage(ordinalFile,thumbnailType.getWidth(),thumbnailType.getHeight(),targetFile);
								}
							}
						}
					}
					resp.setId(id);
					resp.setState("SUCCESS");
					resp.setSize(file.getSize());
					resp.setType(fileFormat);
					resp.setFileName(fileName);
					resp.setOriginalName(originalName);
					resp.setRelativeUrl(StringUtils.join(new Object[] {"/images/", ordinal, hash, fileName }, '/'));
					resp.setUrl(StringUtils.join(new Object[] { domain, resp.getRelativeUrl() }, '/'));
					resp.setHash(String.valueOf(hash));

				} catch (IOException e) {
					resp.setState("图片文件有误，稍后请重试。");
				}
			} else {
				resp.setState("不允许的文件格式");
			}
		}
		return resp;
	}
	
	

	public static class ImgResponseObj {

		private Long id;
		private String fileName;
		private String originalName;
		private long size;
		private String state;
		private String type;
		private String url;
		private String relativeUrl;
		private String hash;
		private Integer width;
		private Integer height;

		public Long getId() {
			return id;
		}

		public void setId(Long id) {
			this.id = id;
		}

		public String getFileName() {
			return fileName;
		}

		public void setFileName(String fileName) {
			this.fileName = fileName;
		}

		public String getOriginalName() {
			return originalName;
		}

		public void setOriginalName(String originalName) {
			this.originalName = originalName;
		}

		public long getSize() {
			return size;
		}

		public void setSize(long size) {
			this.size = size;
		}

		public String getState() {
			return state;
		}

		public void setState(String state) {
			this.state = state;
		}

		public String getType() {
			return type;
		}

		public void setType(String type) {
			this.type = type;
		}

		public String getUrl() {
			return url;
		}

		public void setUrl(String url) {
			this.url = url;
		}

		public String getHash() {
			return hash;
		}

		public void setHash(String hash) {
			this.hash = hash;
		}

		public String getRelativeUrl() {
			return relativeUrl;
		}

		public void setRelativeUrl(String relativeUrl) {
			this.relativeUrl = relativeUrl;
		}

		public Integer getWidth() {
			return width;
		}

		public void setWidth(Integer width) {
			this.width = width;
		}

		public Integer getHeight() {
			return height;
		}

		public void setHeight(Integer height) {
			this.height = height;
		}

	}

}
